import Vue from "vue";
import configs from '@/configs';

/**
 * 获取本地存储
 *
 * @param {string} key 获取数据的键
 * @return {string} 获取数据的值
 */
export const getStorageItem = (key) => {
  if (!key) return
  return window.localStorage.getItem(key);
}
/**
 * 设置本地存储
 *
 * @param {string} key 保存数据的键
 * @param {string} value 保存数据的值
 */
export const setStorageItem = (key, value) => {
  if (!key) return
  if (typeof key !== 'string') {
    key = JSON.stringify(key)
  }
  if (typeof value == 'object') {
    value = JSON.stringify(value);
  }
  window.localStorage.setItem(key, value);
}
/**
 * 移除本地存储
 *
 * @param {string} key 移除数据的键
 */
export const removeStorageItem = (key) => {
  if (!key) return
  window.localStorage.removeItem(key)
}

/**
 * 获取style样式
 */
export const getStyle = (element, attr, NumberMode = 'int') => {
  let target
  // scrollTop 获取方式不同，没有它不属于style，而且只有document.body才能用
  if (attr === 'scrollTop') {
    target = element.scrollTop
  } else if (element.currentStyle) {
    target = element.currentStyle[attr]
  } else {
    target = document.defaultView.getComputedStyle(element, null)[attr]
  }
  // 在获取 opactiy 时需要获取小数 parseFloat
  return NumberMode === 'float' ? parseFloat(target) : parseInt(target)
}

/**
 * 页面到达底部，加载更多
 */
export const loadMore = (element, callback) => {
  const windowHeight = window.screen.height
  let height
  let setTop
  let paddingBottom
  let marginBottom
  let requestFram
  let oldScrollTop

  document.body.addEventListener('scroll', () => {
    loadMore()
  }, false)
  // 运动开始时获取元素 高度 和 offseTop, pading, margin
  element.addEventListener('touchstart', () => {
    height = element.offsetHeight
    setTop = element.offsetTop
    paddingBottom = getStyle(element, 'paddingBottom')
    marginBottom = getStyle(element, 'marginBottom')
  }, { passive: true })

  // 运动过程中保持监听 scrollTop 的值判断是否到达底部
  element.addEventListener('touchmove', () => {
    loadMore()
  }, { passive: true })

  // 运动结束时判断是否有惯性运动，惯性运动结束判断是非到达底部
  element.addEventListener('touchend', () => {
    oldScrollTop = document.body.scrollTop
    moveEnd()
  }, { passive: true })

  const moveEnd = () => {
    requestFram = requestAnimationFrame(() => {
      if (document.body.scrollTop !== oldScrollTop) {
        oldScrollTop = document.body.scrollTop
        loadMore()
        moveEnd()
      } else {
        cancelAnimationFrame(requestFram)
        // 为了防止鼠标抬起时已经渲染好数据从而导致重获取数据，应该重新获取dom高度
        height = element.offsetHeight
        loadMore()
      }
    })
  }

  const loadMore = () => {
    if (document.body.scrollTop + windowHeight >= height + setTop + paddingBottom + marginBottom) {
      callback()
    }
  }
}

/**
 * 显示返回顶部按钮，开始、结束、运动 三个过程中调用函数判断是否达到目标点
 */
export const showBack = callback => {
  let requestFram
  let oldScrollTop

  document.addEventListener('scroll', () => {
    showBackFun()
  }, false)
  document.addEventListener('touchstart', () => {
    showBackFun()
  }, { passive: true })

  document.addEventListener('touchmove', () => {
    showBackFun()
  }, { passive: true })

  document.addEventListener('touchend', () => {
    oldScrollTop = document.body.scrollTop
    moveEnd()
  }, { passive: true })

  const moveEnd = () => {
    requestFram = requestAnimationFrame(() => {
      if (document.body.scrollTop !== oldScrollTop) {
        oldScrollTop = document.body.scrollTop
        moveEnd()
      } else {
        cancelAnimationFrame(requestFram)
      }
      showBackFun()
    })
  }

  // 判断是否达到目标点
  const showBackFun = () => {
    if (document.body.scrollTop > 500) {
      callback(true)
    } else {
      callback(false)
    }
  }
}

/**
 * 运动效果
 * @param {HTMLElement} element   运动对象，必选
 * @param {JSON}        target    属性：目标值，必选
 * @param {number}      duration  运动时间，可选
 * @param {string}      mode      运动模式，可选
 * @param {function}    callback  可选，回调函数，链式动画
 */
export const animate = (element, target, duration = 400, mode = 'ease-out', callback) => {
  clearInterval(element.timer)

  // 判断不同参数的情况
  if (duration instanceof Function) {
    callback = duration
    duration = 400
  } else if (duration instanceof String) {
    mode = duration
    duration = 400
  }

  // 判断不同参数的情况
  if (mode instanceof Function) {
    callback = mode
    mode = 'ease-out'
  }

  // 获取dom样式
  const attrStyle = attr => {
    if (attr === 'opacity') {
      return Math.round(getStyle(element, attr, 'float') * 100)
    } else {
      return getStyle(element, attr)
    }
  }
  // 根字体大小，需要从此将 rem 改成 px 进行运算
  const rootSize = parseFloat(document.documentElement.style.fontSize)

  const unit = {}
  const initState = {}

  // 获取目标属性单位和初始样式值
  Object.keys(target).forEach(attr => {
    if (/[^\d^\.]+/gi.test(target[attr])) {
      unit[attr] = target[attr].match(/[^\d^\.]+/gi)[0] || 'px'
    } else {
      unit[attr] = 'px'
    }
    initState[attr] = attrStyle(attr)
  })

  // 去掉传入的后缀单位
  Object.keys(target).forEach(attr => {
    if (unit[attr] === 'rem') {
      target[attr] = Math.ceil(parseInt(target[attr]) * rootSize)
    } else {
      target[attr] = parseInt(target[attr])
    }
  })

  let flag = true // 假设所有运动到达终点
  const remberSpeed = {}// 记录上一个速度值,在ease-in模式下需要用到
  element.timer = setInterval(() => {
    Object.keys(target).forEach(attr => {
      let iSpeed = 0 // 步长
      let status = false // 是否仍需运动
      const iCurrent = attrStyle(attr) || 0 // 当前元素属性址
      let speedBase = 0 // 目标点需要减去的基础值，三种运动状态的值都不同
      let intervalTime // 将目标值分为多少步执行，数值越大，步长越小，运动时间越长
      let oldspeed = ''
      switch (mode) {
        case 'ease-out':
          speedBase = iCurrent
          intervalTime = duration * 5 / 400
          break
        case 'linear':
          speedBase = initState[attr]
          intervalTime = duration * 20 / 400
          break
        case 'ease-in':
          oldspeed = remberSpeed[attr] || 0
          iSpeed = oldspeed + (target[attr] - initState[attr]) / duration
          remberSpeed[attr] = iSpeed
          break
        default:
          speedBase = iCurrent
          intervalTime = duration * 5 / 400
      }
      if (mode !== 'ease-in') {
        iSpeed = (target[attr] - speedBase) / intervalTime
        iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed)
      }
      // 判断是否达步长之内的误差距离，如果到达说明到达目标点
      switch (mode) {
        case 'ease-out':
          status = iCurrent !== target[attr]
          break
        case 'linear':
          status = Math.abs(Math.abs(iCurrent) - Math.abs(target[attr])) > Math.abs(iSpeed)
          break
        case 'ease-in':
          status = Math.abs(Math.abs(iCurrent) - Math.abs(target[attr])) > Math.abs(iSpeed)
          break
        default:
          status = iCurrent !== target[attr]
      }

      if (status) {
        flag = false
        // opacity 和 scrollTop 需要特殊处理
        if (attr === 'opacity') {
          element.style.filter = 'alpha(opacity:' + (iCurrent + iSpeed) + ')'
          element.style.opacity = (iCurrent + iSpeed) / 100
        } else if (attr === 'scrollTop') {
          element.scrollTop = iCurrent + iSpeed
        } else {
          element.style[attr] = iCurrent + iSpeed + 'px'
        }
      } else {
        flag = true
      }

      if (flag) {
        clearInterval(element.timer)
        if (callback) {
          callback()
        }
      }
    })
  }, 20)
}

/** 检验字符长度
 * @param {value}     字符串,必填
 *@param {len}      长度限制,必填
 */
export const chatLimit = (value, len) => {
  var num = 0 // 总个数累加判断
  for (var i = 0; i < value.length; i++) {
    // 根据charCodeAt来判断输入的是中文还是字母，符号
    const charCode = value.charCodeAt(i)
    if (charCode >= 0 && charCode <= 128) {
      // 字符就+1
      num += 1
    } else {
      // 汉子就+2
      num += 2
    }
  }
  return !(len - num <= 0)
}


//  回到顶部
export function backTop(height = 0) {
  let timer = ''
  timer = setInterval(function () {
    const osTop = document.documentElement.scrollTop || document.body.scrollTop
    const ispeed = Math.floor(-osTop / 5)
    document.documentElement.scrollTop = document.body.scrollTop = osTop + ispeed

    if (osTop <= height) {
      clearInterval(timer)
    }
  }, 10)
}

export function test1() {
  alert('test1111')
}

/**
 * 判断是否有该class
 * @param ele dom元素
 * @param cls class
 * @returns {boolean}
 */
export function has_class(ele, cls) {
  if (ele && cls) {
    var obj_class = ' ' + ele.className + ' '
    // todo待修改
    if (obj_class.indexOf(cls) !== -1) {
      return true
    }
  }
  return false
}

/** *
 * 给dom元素添加class
 * @param ele dom元素
 * @param cls class
 */
export function add_class(ele, cls) {
  if (arguments.length < 2) {
    return
  }
  if (!this.has_class(ele, cls)) {
    var c_name = ele.className
    if (c_name != '') {
      ele.className = c_name + ' ' + cls
    } else {
      ele.className = cls
    }
  }
}

/** *
 * 移除class
 * @param ele dom元素
 * @param cls class
 */
export function remove_class(ele, cls) {
  if (!ele || !this.has_class(ele, cls)) {
    return
  }
  var c_name = ' ' + ele.className + ' '// a1 a12    bca  ca          " a1 dd a12 dac ac tt "
  c_name = c_name.replace(' ' + cls + ' ', ' ')
  c_name = c_name.substring(1, c_name.length - 1) // 去除前后空格
  ele.className = c_name
}
export function deepClone(source) {
  if (!source && typeof source !== 'object') {
    throw new Error('error arguments', 'shallowClone')
  }
  const targetObj = source.constructor === Array ? [] : {}
  Object.keys(source).forEach(keys => {
    if (source[keys] && typeof source[keys] === 'object') {
      targetObj[keys] = source[keys].constructor === Array ? [] : {}
      targetObj[keys] = deepClone(source[keys])
    } else {
      targetObj[keys] = source[keys]
    }
  })
  return targetObj
}

export function hasArrayChild(obj, childrenKey) {
  return obj[childrenKey] && Array.isArray(obj[childrenKey])
}

export function fireEvent(element, event) {
  if (document.createEventObject) {
    // IE浏览器支持fireEvent方法
    const evt = document.createEventObject()
    return element.fireEvent('on' + event, evt)
  } else {
    // 其他标准浏览器使用dispatchEvent方法
    const evt = document.createEvent('HTMLEvents')
    evt.initEvent(event, true, true)
    return !element.dispatchEvent(evt)
  }
}

export function isPromise(obj) {
  return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'
}

/**
 * 数据类型
 *
 * @param {all} data 需要判断的数据
 * @return {string}
 */
export const checkType = function (data) {
  const str = Object.prototype.toString.call(data);
  return str.match(/\[object (.*?)\]/)[1].toLowerCase()
}
/**
 * 是否是字符串
 *
 * @param {all} data 需要判断的数据
 * @return {boolean} true:是 false:不是
 */
export const isString = function (data) {
  return checkType(data) === 'string'
}
/**
 * 去除开头和结尾所有空格
 *
 * @param {all} data 需要去除空格的数据
 * @return {string} 去除空格后的字符串
 */
export const trim = function (data) {
  if (!isString(data)) return data;
  return data.trim()
}
/**
 * 去除开头所有空格
 *
 * @param {all} data 需要去除空格的数据
 * @return {string} 去除空格后的字符串
 */export const trimLeft = function (data) {
  if (!isString(data)) return data;
  return data.trimLeft()
}
/**
 * 去除结尾所有空格
 *
 * @param {all} data 需要去除空格的数据
 * @return {string} 去除空格后的字符串
 */
export const trimRight = function (data) {
  if (!isString(data)) return data;
  return data.trimRight()
}
/**
 * 去除结尾所有空格
 *
 * @param {all} data 需要去除空格的数据
 * @return {string} 去除空格后的字符串
 */
export const trimAll = function (data) {
  if (!isString(data)) return data;
  return data.replace(/\s/g, "");
}
/**
 * 数组倒序
 */
// Array.reverse()
/**
 * 数组按字母或数字顺序(小到大)
 */
// Array.sort()
/**
 * 数组按数字顺序(大到小)
 */
// Array.sort((a,b)=>(b-a))
/**
 * 数组元素位置
 *
 * @param {all} data 数组
 * @param {all} val 数组元素
 * @return {number} 位置 注:-1为数组中不存在该元素
 */
export const indexOfArray = function (data, val) {
  for (let i = 0; i < data.length; i++) {
    if (data[i] === val) return i;
  }
  return -1;
};
/**
 * 数组元素删除
 *
 * @param {all} data 数组
 * @param {all} val 数组元素
 */
export const removeArray = function (data, val) {
  let index = indexOfArray(data, val);
  // let newArr=deepClone(arr);
  if (index > -1) {
    data.splice(index, 1);
  }
  // return newArr
};
/**
 * 数组去重
 *
 * @param {all} data 数组
 * @return {array} 去重后的数组
 */
export const uniqueArray = function (data = []) {
  return [...new Set(data)]
}
/**
 * 数组之间的并集
 *
 * @param {object} args 数组
 * @return {array} 并集后的数组
 */
export function unionArray(...args) {
  return Array.from(new Set([].concat(...args)))
}
/**
 * 数组之间的交集
 *
 * @param {array} a 数组
 * @param {array} b 数组
 * @return {array} 交集后的数组
 */
export function intersectionArray(a = [], b = []) {
  const setB = new Set(b)
  return a.filter((item) => {
    return setB.has(item)
  })
}
/**
 * 数组之间的差集
 *
 * @param {array} a 数组
 * @param {array} b 数组
 * @return {array} 差集后的数组
 */
export function diffsetArray(a = [], b = []) {
  const setB = new Set(b)
  const setA = new Set(a)
  return [...([...a].filter((item) => {
    return !setB.has(item)
  })), ...([...b].filter((item) => {
    return !setA.has(item)
  }))]
}
/**
 * 元素在数组或者字符串里存在的次数
 *
 * @param {array,string} target 数组|字符串
 * @param {all} s 元素
 * @return {number} 次数
 */
export function calcQuantity(target, s) {
  const newTarget = typeof target === 'string' ? target.split('') : target
  return newTarget.reduce((t, c) => {
    return s === c ? t + 1 : t
  }, 0)
}

/**
 * 判断是否是 Object
 *
 * @param {Object} obj 需要判断的对象
 * @return {Boolean} true:是Object false:不是Object
 */
export function isObject(obj) {
  return checkType(obj) === 'object'
}

/**
 * 判断是否是 空Object
 *
 * @param {Object} obj 需要判断的对象
 * @return {Boolean} true:空 false:非空
 */
export function isEmptyObject(obj) {
  if (!isObject(obj)) {
    return false
  }
  return Object.keys(obj).length === 0
}
/**
 * 拼接路径
 *
 * @param {string} str
 * @return {string} str
 */
export function getFullPath(str) {
  return str ? configs.HTTP_URL + str : ''
}
export function getImgPath(str) {
  return str ? configs.STATIC_URL + str : ''
}
/**
 * 深拷贝
 */
// export function deepClone(obj) {
//   const result = {}
//   const keys = Object.keys(obj)
//   let type
//   for (let k of keys) {
//     type = checkType(obj[k])
//     switch (type) {
//       case 'object':
//         result[k] = deepClone(obj[k])
//         break
//       case 'array':
//         result[k] = [].concat(obj[k])
//         break
//       default:
//         result[k] = obj[k]
//     }
//   }
//   return result
// }
/**
 * 文件下载
 *
 * @param {fn} customAxios 默认axios方法
 * @param {str} mid mongoId
 * @param {str} name 文件名(名称.格式)
 * @param {str} url 下载相对路径
 * @param {str} baseUrl 下载主路径
 * @return {string} str
 */
export function downLoadFile(customAxios, mid, name, url = 'api/mongodb/download/', baseUrl = configs.HTTP_URL, word) {
  if (customAxios && mid && url && name) {
    customAxios({
      method: 'get',
      url: url + mid,
      baseURL: baseUrl,
      responseType: 'blob'
    }).then(response => {
      if (!response) {
        console.log('下载失败!')
        return false
      }
      let url = window.URL.createObjectURL(new Blob([response]));
      if (word) {
        url = window.URL.createObjectURL(new Blob([response], { type: word }));
      }
      let link = document.createElement('a');
      link.style.display = 'none';
      link.href = url;
      link.setAttribute('download', name);
      document.body.appendChild(link);
      link.click();
      link.remove();
      return true
    })
  } else {
    console.log('请检查入参是否完整')
  }
}
/**
 * 获取下载地址
 *
 * @param {str} path 下载地址路径
 * @return {str} str
 */
export function getUpLoadFileUrl(path = 'api/mongodb/upload/file') {
  return trimAll(path) ? configs.HTTP_URL + path : null;
}
/**
 * 上传接口获取header参数
 */
// export function getUploadHeaderParams() {
//   return {
//     systemType: configs.SYSTEM_TYPE,
//     CompanyId: VueCookies.get("company"),
//     Authorization: user.authorization()
//   }
// }
/**
 * 获取按钮总数
 *
 * @param {number} amount 默认按钮数（不受权限控制）
 * @param {Array} rights 权限数组['q1','q2']
 * @return {number} count 总数
 */
export function getButtonCount(amount = 3, rights = []) {
  return amount + rights.length;
}
/**
 * 获取按钮总数
 *
 * @param {Array} tree 数组（tree）
 * @return {Array} defaultTreeId 需要展开的最底层的IDlist
 * @return {Array} treeObj 找到最底层的treeItem
 */
export function getExpandedTree(tree = []) {
  let treeObj;
  let defaultTreeId = [];
  function forTree(treeItem) {
    defaultTreeId.push(treeItem.id);
    if (treeItem.children) {
      forTree(treeItem.children[0]);
    } else {
      treeObj = treeItem;
    }
  }
  forTree(tree[0]);
  return { defaultTreeId, treeObj };
}
export function numFilter(val) {
  if (Number(val)) {
    const realVal = parseFloat(val).toFixed(2);
    return realVal;
  } else {
    return val
  }
}
/**
     * @description: 数组去重
     * @param {arr} 需要传入的数组
     * @param {type} 匹配的唯一标识字段
     * @return 没有返回信息写 void / 有返回信息 {返回类型} 描述信息
     */
export function setArr(arr, type) {
  if (arr.length == 0) {
    return arr
  } else {
    if (type) {
      var obj = {}
      var newArr = arr.reduce((cur, next) => {
        obj[next.id] ? '' : obj[next.id] = true && cur.push(next)
        return cur
      }, [])
      return newArr
    } else {
      return Array.from(new Set(arr))
    }
  }
}
export function deweight(arr, key) {
  let res = []
  arr.forEach((item) => {
    let list = []
    res.forEach((resitem) => {
      list.push(resitem[key])
    })
    if (list.indexOf(item[key]) === -1) {
      res.push(item)
    }
  })
  return res
}

export const downLoadAxios = async (url = "", data = {}, type = "post", isJson = false, host = configs.HTTP_URL, params) => {
  let mess = await Vue.prototype.$axios({
      method: type,
      url: host + url,
      data: data,
      params,
      responseType: "blob",
      withCredentials: false,
      headers: { isJson: isJson },
    }).then((res) => {
      return res;
    });
  return mess;
};
// 下载方法
export function downloadLink(data, name) {
  let url = window.URL.createObjectURL(new Blob([data]), {type:'application/vnd.ms-excel'});
  let link = document.createElement("a");
  link.style.display = "none";
  link.href = url;
  link.download = name;
  document.body.appendChild(link);
  link.click();
  link.remove();
};